/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package shaman.storage.impl.stream.gather;

import java.io.IOException;
import java.io.InputStream;
import shaman.storage.impl.stream.size.SizeLimitInputStream;

/**
 *
 * @author dmitriy
 */
public class ScatterInputStream {

    private final InputStreamSource source;
    private InputStream baseStream;
    private boolean streamOpen=false;
    private long offset=0;

    private class PartInputStream extends SizeLimitInputStream {

        public PartInputStream(long endOffset) {
            super(baseStream, endOffset-offset);
            closeBaseStream=false;
        }

        @Override
        public synchronized void close() throws IOException {
            if (isClosed()==false)
            {
                super.close();
                streamOpen=false;
                offset+=getOffset();
            }
        }

    }

    public ScatterInputStream(InputStream baseStream) {
        this.baseStream=baseStream;
        source=null;
    }

    public ScatterInputStream(InputStreamSource source) {
        baseStream=null;
        this.source=source;
    }

    public synchronized InputStream nextPart(long startOffset, long length) throws IOException
    {
        if (streamOpen)
            throw new IOException("A stream is already opened");
        streamOpen=true;
        if (baseStream!=null && startOffset>=offset) {
            while (offset<startOffset)
            {
                long len=baseStream.skip(startOffset-offset);
                if (len>=0)
                    offset+=len;
                else
                    throw new IOException("Unable to seek");
            }
        } else if (source!=null) {
            if (baseStream!=null)
                baseStream.close();
            baseStream=source.getInputStream(startOffset);
            offset=startOffset;
        } else if (baseStream!=null) {
            throw new IOException("Cannot move backwards");
        } else {
            throw new IOException("Stream is closed");
        }
        long endOffset=startOffset+length;
        if (endOffset<startOffset)
            endOffset=Long.MAX_VALUE;
        return new PartInputStream(endOffset);
    }

    public void close() throws IOException {
        InputStream base=this.baseStream;
        this.baseStream=null;
        base.close();
    }
}
